package com.lb.base.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.Map;

@Slf4j
@Component
public class RestTemplateClient {

    private static RestTemplate restTemplate;

    public RestTemplateClient(RestTemplate restTemplate) {RestTemplateClient.restTemplate = restTemplate;}

    public Void postByJson(@NonNull String url, final Object requestBody){
        return this.postByJson(url, requestBody, new ParameterizedTypeReference<Void>() {});
    }

    public <T> T postByJson(@NonNull String url, final Object requestBody, @NonNull ParameterizedTypeReference<T> responseBodyType){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity requestEntity = new HttpEntity<>(requestBody, headers);
        return this.exchange(url, HttpMethod.POST, requestEntity, responseBodyType);
    }

    public Void postByFormUrlencoded(@NonNull String url, final Map<String, Object> requestParams){
        return this.postByFormUrlencoded(url, requestParams, new ParameterizedTypeReference<Void>() {});
    }

    public <T> T postByFormUrlencoded(@NonNull String url, final Map<String, Object> requestParams, @NonNull ParameterizedTypeReference<T> responseBodyType){
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>(requestParams.size());
        for(Map.Entry<String, Object> entry : requestParams.entrySet()){
            if(entry.getKey() == null || entry.getValue() == null){
                continue;
            }
            map.add(entry.getKey(), entry.getValue());
        }
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
        return this.exchange(url, HttpMethod.POST, requestEntity, responseBodyType);
    }

    public Void get(String url){
        return this.get(url, null, new ParameterizedTypeReference<Void>() {});
    }

    public Void get(String url, final Map<String, Object> requestParams){
        return this.get(url, requestParams, new ParameterizedTypeReference<Void>() {});
    }

    public <T> T get(String url, ParameterizedTypeReference<T> responseBodyType){
        HttpHeaders requestHeaders = new HttpHeaders();
        HttpEntity<?> requestEntity = new HttpEntity<>(requestHeaders);
        return this.exchange(url, HttpMethod.GET, requestEntity, responseBodyType);
    }

    public <T> T get(String url, final Map<String, Object> requestParams, @NonNull ParameterizedTypeReference<T> responseBodyType){
        HttpHeaders requestHeaders = new HttpHeaders();
        HttpEntity<HttpHeaders> requestEntity = new HttpEntity<>(requestHeaders);
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
        if(requestParams != null){
            for(Map.Entry<String, Object> entry : requestParams.entrySet()){
                if(entry.getKey() == null || entry.getValue() == null){
                    continue;
                }
                uriBuilder.queryParam(entry.getKey(), entry.getValue());
            }
        }
        return this.exchange(uriBuilder.build().toUriString(), HttpMethod.GET, requestEntity, responseBodyType);
    }

    private <T> T exchange(String url, HttpMethod httpMethod, HttpEntity requestEntity, @NonNull ParameterizedTypeReference<T> responseBodyType){
        ResponseEntity<T> responseEntity = null;
        try {
            log.info("restTemplateClient请求: {}", url);
            responseEntity = restTemplate.exchange(url, httpMethod, requestEntity, responseBodyType);
        }catch (HttpClientErrorException e){
            log.error("远程服务调用错误", e);
        }
        if(responseEntity != null){
            return responseEntity.getBody();
        }
        return null;
    }

}
